浮点数和机器精度 | 您所在的位置:网站首页 › 浮点 精度 › 浮点数和机器精度 |
在优化代码的过程中再次遇到数据瓶颈——精度问题,不得不再温习一下这个自以为很了解的主题:浮点数和精度。 为什么一个简单的整数,在计算机内的值并不一致?例如,实际数值558783388,在float下是558783360,而 log2( 558783388) ans = 29.0577 log2( 558783360) ans = 29.0577在double下是5.587833745970526e+08,因为double精度比float高,所以更加逼近实际数值 误差
这一切就是因为二进制,用二进制表示一个数(十进制数),是有误差的。再举一个例子: double a=0.2;在内存中,我们可以看到a对应的存储区数据是: 9A 99 99 99 99 99 C9 3F这是小端(little endian)存储方式,换成高位在前: 3F C9 99 99 99 99 99 9Adouble在内存中的形式如下(详细请看IEEE 754浮点运算标准): 63(1 bits) 62~52(11 bits) 51~0(52 bits) 符号位 指数位(阶码) 尾数 (-1022~1023)可见符号位为0,指数位是0x3FC,即1020,减去2^10-1,即1023,得指数为-3;尾数是999999999999A。所以完整的数字就是16进制的1.999999999999A乘上2^-3,得 a=0.2000 0000 0000 0000 1110 2230 2462 5157已经可以看到用double表示0.2时存在的误差。这个例子说明在用有限字长的二进制浮点数表示任意实数a可能引入误差。设实数a的指数为e,尾数位数为n,显然:误差1的最小浮点数ε。显然double的机器精度是1/2^52。float的机器精度是1/2^23。上面的例子就是,十进制数的0.2后面第17位开始有误差,即10^-16: 10^-16 ans = 1.0000e-16 2^-52 ans = 2.2204e-16double而今不足以确定其精度,其最小只能到: 10^-15 ans = 1.0000e-15上面说的是小数位,更科学的说法是有效数字。因为小数点前默认有个1,所以float的有效数字是24bit,对应8位十进制有效数字; double的有效数字是53bit,对应16位十进制有效数字。也就是说,如果一个实数的有效数字超过8位,用单精度浮点数来表示的话,就会产生误差!同样,如果一个实数的有效数字超过16位,用双精度浮点数来表示,也会产生误差!NaN和INF 在matlab中经常遇到,计算后的矩阵中存在这两个符号。它们属于特殊的浮点数。一旦阶码为0或全1,就会出现特殊浮点数。
# 当指数全0的情况下,如果尾数为0,根据符号位不同可以分为+0和-0;如果尾数为非0,即尾数部分不假设前面存在小数点前的1。或者说这些数太接近0了,因为指数已经不能再小。例如一个double变量在内存中的表示(十六进制): 00 00 00 00 00 00 00 01阶码为0,指数直接等于-1022,尾数为1/2^52,故结果为: 4.9406564584124654e-324 # 当指数全1的情况下,如果尾数为0,表示无穷,根据符号位确定是+INF、-INF;如果尾数非0,表示NaN非数值
归纳如下表:浮点数的特殊值(double) 符号位 阶码 尾数 数值 0 0 0 +0 1 0 0 -0 0 2047 0 +∞ 1 2047 0 -∞ 0 2047 非0 NaN 总结float和int都是32bit,但float的尾数只用了23bit。int的精度高于float,float的表示范围大于int。float牺牲精度换取了更大的表示范围。 double的尾数是52bit,高于32bit的int,所以用dobule表示int不会有精度损失。 double是科学计算的常用类型,了解double的内在和限制,有助于我们更好地使用它。 |
CopyRight 2018-2019 实验室设备网 版权所有 |